package mdt.program;

import mdt.utils.DemoGraphLoader;
import org.tigris.gef.base.Diagram;
import org.tigris.gef.base.Editor;
import org.tigris.gef.base.Globals;
import org.tigris.gef.graph.GraphModel;
import org.tigris.gef.graph.GraphModelException;
import org.tigris.gef.graph.MutableGraphSupport;
import org.tigris.gef.graph.presentation.JGraph;
import org.tigris.gef.presentation.TextEditor;
import sun.awt.SunHints;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Created by xiaobyu on 7/19/2016.
 */
public class GraphManager {

    private static int untitledIndex = 1;
    private static GraphInfo activeGraphInfo;

    public static final String DEMO_TITLE = "Demo Graph";


    static MDTRenderer renderer = new MDTRenderer();

    static Map<JGraph, GraphInfo> graphInfoMap = new HashMap<>();

    static {
        MutableGraphSupport.setSaveAction(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //TODO
            }

            public void setEnabled(boolean newValue) {
                if (activeGraphInfo == null) return;

                activeGraphInfo.setDirty(true);
                Displayer.instance().updateTabGraphDirtyFlag(activeGraphInfo.graph, activeGraphInfo.getTitle(), activeGraphInfo.isDirty());
            }
        });
    }

    public static int getNextTitleIndex() {
        return untitledIndex++;
    }

    public static void graphSelected(JGraph graph) {
        if (graph != null) {
            Globals.curEditor(graph.getEditor());
            setActiveGraphInfo(graphInfoMap.get(graph));
        } else {
            Globals.curEditor(null);
            setActiveGraphInfo(null);
        }
    }

    public static void setActiveGraphInfo(GraphInfo info) {
        if (activeGraphInfo != null) {
            TextEditor te = activeGraphInfo.editor.getActiveTextEditor();
            if (te != null) {
                te.endEditing();
            }
        }
        activeGraphInfo = info;
    }

    public static Collection<GraphInfo> getGraphInfos() {
        return graphInfoMap.values();
    }

    public static GraphInfo getGraphInfo(JGraph graph) {
        return graphInfoMap.get(graph);
    }

    public static GraphInfo getActiveGraphInfo() {
        return activeGraphInfo;
    }

    public static GraphInfo newGraph(boolean loadDemo) {
        String title = "new " + getNextTitleIndex();
        MDTGraphModel model = new MDTGraphModel();
        Diagram diagram = new Diagram(title, model);
        JGraph graph = new JGraph(diagram);

        try {
            model.setConnectionConstrainer(ConnectionConstrainer.getInstance());
        } catch (GraphModelException e) {
            e.printStackTrace();
        }

        GraphInfo info = addGraph(graph, diagram, title, null);
        Displayer.instance().selectTab(graph);
        if (loadDemo) {
            DemoGraphLoader.loadDemoGraph(info);
        }
        return info;
    }

    public static void removeGraph(JGraph graph) {

        GraphInfo info = graphInfoMap.remove(graph);
        if (info != null) {
            Displayer.instance().closeGraphTab(info.graph);
        }
    }

    public static GraphInfo addGraph(JGraph graph, Diagram diagram, String title, File file) {
        GraphInfo graphInfo = new GraphInfo(title);
        graphInfo.diagram = diagram;
        graphInfo.editor = graph.getEditor();
        graphInfo.graph = graph;
        graphInfo.file = file;
        graphInfoMap.put(graph, graphInfo);
        setActiveGraphInfo(graphInfo);

        graph.setGraphNodeRenderer(renderer);
        graph.setGraphEdgeRenderer(renderer);

        graph.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                Displayer.instance().dismissWarningMessage();
            }
        });
        graph.addModeChangeListener(Displayer.instance());
        graph.getEditor().setRenderingHits(RenderingHints.KEY_ANTIALIASING, SunHints.VALUE_ANTIALIAS_ON);
        Displayer.instance().addTab(title, graph);
        return graphInfo;
    }

    public static Diagram getActiveDiagram() {
        return activeGraphInfo.diagram;
    }


    public static GraphInfo getGraphByFile(File file) {
        for (GraphInfo info : graphInfoMap.values()) {
            if (info.file != null && info.file.equals(file)) {
                return info;
            }
        }
        return null;
    }

    public static GraphInfo getGraphByModel(GraphModel model) {
        for (GraphInfo info : graphInfoMap.values()) {
            if (info.diagram.getGraphModel() == model) {
                return info;
            }
        }
        return null;
    }


    public static class GraphInfo {
        private String title;
        public JGraph graph;
        public Diagram diagram;
        public Editor editor;
        public File file;
        private boolean dirty = false;

        public GraphInfo(String title) {
            this.title = title;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
            Displayer.instance().updateTabGraphDirtyFlag(graph, title, dirty);
        }

        public boolean isDirty() {
            return dirty;
        }

        public void setDirty(boolean dirty) {
            this.dirty = dirty;
        }
    }

    static Properties properties;
    static File propFile;

    static {
        properties = new Properties();
        File mdtDir = new File(System.getProperty("user.home") + File.separator + ".mdt");
        propFile = new File(mdtDir, "config.properties");
        if (!mdtDir.exists() || !mdtDir.isDirectory()) {
            mdtDir.mkdirs();
        } else {
            if (propFile.exists()) {
                try {
                    properties.load(new FileReader(propFile));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static final String PROP_LAST_DIR = "runtime.lastDirectory";
    public static final String PROP_LOAD_DEMO_AT_STARTUP = "config.loadDemoAtStartup";
    public static void setLastVisitedDir(String directory) {
        Globals.setLastDirectory(directory);

        String old = properties.getProperty(PROP_LAST_DIR);
        if (old != null && old.equals(directory)) return;

        properties.setProperty(PROP_LAST_DIR, directory);
        storeProperties();
    }

    public static String getLastVisitedDir() {
        String lastDir = properties.getProperty(PROP_LAST_DIR);
        if (lastDir == null) {
            lastDir = System.getProperty("user.home");
            setLastVisitedDir(lastDir);
        }
        return lastDir;
    }

    private static void storeProperties() {
        try {
            properties.store(new FileWriter(propFile), "saving properties");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean loadDemoAtStartup() {
        String str = properties.getProperty(PROP_LOAD_DEMO_AT_STARTUP);
        if (str == null) {
            str = "true";
        }
        return Boolean.parseBoolean(str);
    }



}
